package edu.towson.cosc.cosc455.interfacesOIMANI1markdowncompiler;

import edu.towson.cosc.cosc455.interfaces.SyntaxAnalyzer;

import java.lang.*;
import java.util.*;

public class MySyntaxAnalyzer implements SyntaxAnalyzer {
	Queue<String> parseTree = new LinkedList<String>();
	private MyLexicalAnalyzer lexims;
	String r;
	String extra;
	public Queue<String> getQueue() {
		return parseTree;
		}
	
	@Override
	public void document() throws CompilerException {
		// TODO Auto-generated method stub
       if(!MyCompilerClass.currentToken.equalsIgnoreCase("#Start Document"))
       {
       String message = (" A #Start Document Tag was expected but not found" +
                       MyCompilerClass.currentToken + "was found instead");
           throw new CompilerException(message);
       }
       parseTree.add(MyCompilerClass.currentToken);
       lexims.getNextToken();
       if (MyCompilerClass.currentToken.equalsIgnoreCase("#Start Define")){
    	   define(); 
    	   }
       if (MyCompilerClass.currentToken.equalsIgnoreCase("#Start Head")){
    	   head(); 
    	   }
    	   body(); 
       if(!MyCompilerClass.currentToken.equalsIgnoreCase("#End Document"))
       {
       String message = (" A #End Document Tag was expected but not found" +
                       MyCompilerClass.currentToken + "was found instead");
           throw new CompilerException(message);
       }
       lexims.getNextToken();
       if(!MyCompilerClass.currentToken.isEmpty())
       {
           String message = (" This was suppose to be the end of a file but a token was found instead");
       throw new CompilerException(message);
       }
       
	}
	
	// This method implements the BNF rule for the body
	// <inner-text><body> | <paragraph><body> | <bold><body> | <italics><body> | <lists><body> | null

	@Override
	public void body() throws CompilerException {
		// TODO Auto-generated method stub
		while (MyCompilerClass.currentToken.equalsIgnoreCase("#NewLine") 
                || MyCompilerClass.currentToken.equalsIgnoreCase("#Start Use") 
                || Character.isLetterOrDigit(MyCompilerClass.currentToken.charAt(0)) 
                || MyCompilerClass.currentToken.charAt(0) == ' ' || MyCompilerClass.currentToken.equalsIgnoreCase("#Start Paragraph") 
                || MyCompilerClass.currentToken.equalsIgnoreCase("#Start Bold") 
                || MyCompilerClass.currentToken.equalsIgnoreCase("#Start Italics") 
                || MyCompilerClass.currentToken.equalsIgnoreCase("#Start List") ){
		if(MyCompilerClass.currentToken.equalsIgnoreCase("#NewLine") 
				                            || MyCompilerClass.currentToken.equalsIgnoreCase("#Start Use") 
				                            || Character.isLetterOrDigit(MyCompilerClass.currentToken.charAt(0)) 
				                            || MyCompilerClass.currentToken.charAt(0) == ' '){
			innertext();
		}
		innertext();
		if(MyCompilerClass.currentToken.equalsIgnoreCase("#Start Paragraph"))
		{
		paragraph();
		}
		if(MyCompilerClass.currentToken.equalsIgnoreCase("#Start Bold"))
		{
		bold();
		}
		if(MyCompilerClass.currentToken.equalsIgnoreCase("#Start Italics"))
		{
		italics();
		}
		if(MyCompilerClass.currentToken.equalsIgnoreCase("#Start List"))
		{
		list();
		}
	   }
		
	}

	// This method implements the BNF rule for the head
	// #START HEAD <title> #END HEAD | null
	@Override
	public void head() throws CompilerException {
		// TODO Auto-generated method stub
	       if(!MyCompilerClass.currentToken.equalsIgnoreCase("#Start Head"))
	       {
	       String message = (" A #Start Head Tag was expected but not found" +
	                       MyCompilerClass.currentToken + "was found instead");
	           throw new CompilerException(message);
	       }
	       parseTree.add(MyCompilerClass.currentToken);
	       lexims.getNextToken();
	       if(MyCompilerClass.currentToken.equalsIgnoreCase("#Start Title"))
	         {
	    	   title();
	    	   parseTree.add(MyCompilerClass.currentToken);
	    	   lexims.getNextToken();
	         }     
	       if(!MyCompilerClass.currentToken.equalsIgnoreCase("#End Head"))
	       {
	       String message = (" A #End Head Tag was expected but not found" +
	                       MyCompilerClass.currentToken + "was found instead");
	           throw new CompilerException(message);
	       }
	       parseTree.add(MyCompilerClass.currentToken);
	       lexims.getNextToken();
	}
	
	// This method implements the BNF rule for the head
	// #START TITLE <text> #END TITLE | null
	@Override
	public void title() throws CompilerException {
		// TODO Auto-generated method stub
	       if(!MyCompilerClass.currentToken.equalsIgnoreCase("#Start Title"))
	       {
	       String message = (" A #Start Title Tag was expected but not found" +
	                       MyCompilerClass.currentToken + "was found instead");
	           throw new CompilerException(message);
	       }
	       parseTree.add(MyCompilerClass.currentToken);
	       lexims.getNextToken();
	       if(text())
	         {
	    	   parseTree.add(MyCompilerClass.currentToken);
	    	   lexims.getNextToken();
	         }  
	       
	       if(!MyCompilerClass.currentToken.equalsIgnoreCase("#End Title"))
	       {
	       String message = (" A #End Title Tag was expected but not found" +
	                       MyCompilerClass.currentToken + "was found instead");
	           throw new CompilerException(message);
	       }
	       parseTree.add(MyCompilerClass.currentToken);
	       lexims.getNextToken();

	}
	
	// This method implements the BNF rule for the paragraph
	// #START PARAGRAPH <variable-define> <inner-paragraph> #END PARAGRAPH
	@Override
	public void paragraph() throws CompilerException {
		// TODO Auto-generated method stub
	       if(!MyCompilerClass.currentToken.equalsIgnoreCase("#Start Paragraph"))
	       {
	       String message = (" A #Start Paragraph Tag was expected but not found" +
	                       MyCompilerClass.currentToken + "was found instead");
	           throw new CompilerException(message);
	       }
	       parseTree.add(MyCompilerClass.currentToken);
	       lexims.getNextToken();
	       define();
	       innerparagraph();
	       
	       if(!MyCompilerClass.currentToken.equalsIgnoreCase("#End Paragraph"))
	       {
	       String message = (" A #End Paragraph Tag was expected but not found" +
	                       MyCompilerClass.currentToken + "was found instead");
	           throw new CompilerException(message);
	       }
	       parseTree.add(MyCompilerClass.currentToken);
	       lexims.getNextToken();

	}
    
	// This method implements the BNF rule for the bold
	// #START BOLD <variable-define> <inner-text> #END BOLD 
	@Override
	public void bold() throws CompilerException {
		// TODO Auto-generated method stub
	       if(!MyCompilerClass.currentToken.equalsIgnoreCase("#Start Bold"))
	       {
	       String message = (" A #Start Bold Tag was expected but not found" +
	                       MyCompilerClass.currentToken + "was found instead");
	           throw new CompilerException(message);
	       }
	       parseTree.add(MyCompilerClass.currentToken);
	       lexims.getNextToken();
	       define();
	       innertext();
	       
	       if(!MyCompilerClass.currentToken.equalsIgnoreCase("#End Bold"))
	       {
	       String message = (" A #End Bold Tag was expected but not found" +
	                       MyCompilerClass.currentToken + "was found instead");
	           throw new CompilerException(message);
	       }
	       parseTree.add(MyCompilerClass.currentToken);
	       lexims.getNextToken();

	}
    
	// This method implements the BNF rule for the italics
	// #START ITALICS <variable-define> <inner-text> #END ITALICS  
	@Override
	public void italics() throws CompilerException {
		// TODO Auto-generated method stub
	       if(!MyCompilerClass.currentToken.equalsIgnoreCase("#Start Italics"))
	       {
	       String message = (" A #Start Italics Tag was expected but not found" +
	                       MyCompilerClass.currentToken + "was found instead");
	           throw new CompilerException(message);
	       }
	       parseTree.add(MyCompilerClass.currentToken);
	       lexims.getNextToken();
	       define();
	       innertext();  
	       
	       if(!MyCompilerClass.currentToken.equalsIgnoreCase("#End Italics"))
	       {
	       String message = (" A #End Italics Tag was expected but not found" +
	                       MyCompilerClass.currentToken + "was found instead");
	           throw new CompilerException(message);
	       }
	       parseTree.add(MyCompilerClass.currentToken);
	       lexims.getNextToken();

	}

	// This method implements the BNF rule for the list
	// #START LIST #START ITEM <variable-define> <inner-list> #END ITEM <list-items> #END LIST 
	@Override
	public void list() throws CompilerException {
		// TODO Auto-generated method stub
	       if(!MyCompilerClass.currentToken.equalsIgnoreCase("#Start List"))
	       {
	       String message = (" A #Start List Tag was expected but not found" +
	                       MyCompilerClass.currentToken + "was found instead");
	           throw new CompilerException(message);
	       }
	       parseTree.add(MyCompilerClass.currentToken);
	       lexims.getNextToken();
	       item();
	       
	       if(!MyCompilerClass.currentToken.equalsIgnoreCase("#End List"))
	       {
	       String message = (" A #End List Tag was expected but not found" +
	                       MyCompilerClass.currentToken + "was found instead");
	           throw new CompilerException(message);
	       }
	       parseTree.add(MyCompilerClass.currentToken);
	       lexims.getNextToken();

	}
	
	// This method implements the BNF rule for the item
	// #START ITEM <variable-define> <inner-list> #END ITEM <list-items> | null
	@Override
	public void item() throws CompilerException {
		// TODO Auto-generated method stub
	       if(!MyCompilerClass.currentToken.equalsIgnoreCase("#Start Item"))
	       {
	       String message = (" A #Start Item Tag was expected but not found" +
	                       MyCompilerClass.currentToken + "was found instead");
	           throw new CompilerException(message);
	       }
	       parseTree.add(MyCompilerClass.currentToken);
	       lexims.getNextToken();
	       define();
	       innerlist();
	       
	       if(!MyCompilerClass.currentToken.equalsIgnoreCase("#End Item"))
	       {
	       String message = (" A #End Item Tag was expected but not found" +
	                       MyCompilerClass.currentToken + "was found instead");
	           throw new CompilerException(message);
	       }
	       parseTree.add(MyCompilerClass.currentToken);
	       lexims.getNextToken();

	}

	// This method implements the BNF rule for the audio
	// #START AUDIO <text> #END AUDIO | null
	@Override
	public void audio() throws CompilerException {
		// TODO Auto-generated method stub
	       if(!MyCompilerClass.currentToken.equalsIgnoreCase("#Start Audio"))
	       {
	       String message = (" A #Start Audio Tag was expected but not found" +
	                       MyCompilerClass.currentToken + "was found instead");
	           throw new CompilerException(message);
	       }
	       parseTree.add(MyCompilerClass.currentToken);
	       lexims.getNextToken();
	       if(text())
	         {
	    	   parseTree.add(MyCompilerClass.currentToken);
	    	   lexims.getNextToken();
	         }  
	       
	       if(!MyCompilerClass.currentToken.equalsIgnoreCase("#End Audio"))
	       {
	       String message = (" A #End Audio Tag was expected but not found" +
	                       MyCompilerClass.currentToken + "was found instead");
	           throw new CompilerException(message);
	       }
	       parseTree.add(MyCompilerClass.currentToken);
	       lexims.getNextToken();

	}
    
	// This method implements the BNF rule for the video
	// #START VIDEO <text> #END VIDEO | null
	@Override
	public void video() throws CompilerException {
		// TODO Auto-generated method stub
	       if(!MyCompilerClass.currentToken.equalsIgnoreCase("#Start Video"))
	       {
	       String message = (" A #Start Document Tag was expected but not found" +
	                       MyCompilerClass.currentToken + "was found instead");
	           throw new CompilerException(message);
	       }
	       parseTree.add(MyCompilerClass.currentToken);
	       lexims.getNextToken();
	       if(text())
	         {
	    	   parseTree.add(MyCompilerClass.currentToken);
	    	   lexims.getNextToken();
	         }  
	       
	       if(!MyCompilerClass.currentToken.equalsIgnoreCase("#End Video"))
	       {
	       String message = (" A #End Video was expected but not found" +
	                       MyCompilerClass.currentToken + "was found instead");
	           throw new CompilerException(message);
	       }
	       parseTree.add(MyCompilerClass.currentToken);
	       lexims.getNextToken();

	}
	
	// This method implements the BNF rule for the define, and all tags with in it
	// #START DEFINE #NAME <text> #VALUE <text> #END DEFINE <variable-define> | null
	@Override
	public void define() throws CompilerException {
		// TODO Auto-generated method stub
		while(MyCompilerClass.currentToken.equalsIgnoreCase("#Start Define")){
	       //if(!MyCompilerClass.token.equalsIgnoreCase("#Start Define"))
	       //{
	       //	   String message = (" A #Start Document Tag was expected but not found" +
           //            MyCompilerClass.token + "was found instead");
           //throw new CompilerException(message);
	       //}
			parseTree.add(MyCompilerClass.currentToken);
	       lexims.getNextToken();
	       if(!MyCompilerClass.currentToken.equalsIgnoreCase("#Name"))
	       {
	           String message = (" A #Start Document Tag was expected but not found" +
	                       MyCompilerClass.currentToken + "was found instead");
	        throw new CompilerException(message);
	    	}
	       parseTree.add(MyCompilerClass.currentToken);
	       lexims.getNextToken();
	       if(text())
	         {
	    	   parseTree.add(MyCompilerClass.currentToken);
	    	   lexims.getNextToken();
	         } 	    	   
	       if(!MyCompilerClass.currentToken.equalsIgnoreCase("#Value"))
	       {
	           String message = (" A #Value Tag was expected but not found" +
	                       MyCompilerClass.currentToken + "was found instead");
	        throw new CompilerException(message);
	    	}
	       parseTree.add(MyCompilerClass.currentToken);
	       lexims.getNextToken();
	       if(text())
	         {
	    	   parseTree.add(MyCompilerClass.currentToken);
	    	   lexims.getNextToken();
	         }  
	    	if(!MyCompilerClass.currentToken.equalsIgnoreCase("#End Define"))
	    	   {
	           String message = (" A #End Define Tag was expected but not found" +
	                       MyCompilerClass.currentToken + "was found instead");
	           throw new CompilerException(message);
	    	   }
	    	parseTree.add(MyCompilerClass.currentToken);
	    	lexims.getNextToken();
		}
	}
	
	// This method implements the BNF rule for the use
	// #START USE <text> #END USE | null
	@Override
	public void use() throws CompilerException {
		// TODO Auto-generated method stub
	       if(!MyCompilerClass.currentToken.equalsIgnoreCase("#Start Use"))
	       {
	       String message = (" A #Start Use Tag was expected but not found" +
	                       MyCompilerClass.currentToken + "was found instead");
	           throw new CompilerException(message);
	       }
	       parseTree.add(MyCompilerClass.currentToken);
	       lexims.getNextToken();
	       if(text())
	         {
	    	   parseTree.add(MyCompilerClass.currentToken);
	    	   lexims.getNextToken();
	         }  
	       
    	   if(!MyCompilerClass.currentToken.equalsIgnoreCase("#End Use"))
    	   {
       String message = (" A #End Use Tag was expected but not found" +
                       MyCompilerClass.currentToken + "was found instead");
           throw new CompilerException(message);
    	   }
    	   parseTree.add(MyCompilerClass.currentToken);
    	   lexims.getNextToken();

	}
	// <inner-text> <inner-paragraph> | <bold> <inner-paragraph> | <italics> <inner-paragraph> 
	// | <list> <inner-paragraph> | <newline> <inner-paragraph> | null
	//UNFINISHED!!
	public void innerparagraph() throws CompilerException {
		// TODO Auto-generated method stub
		while(MyCompilerClass.currentToken.equalsIgnoreCase("#NewLine") 
                || MyCompilerClass.currentToken.equalsIgnoreCase("#Start Use") 
                || Character.isLetterOrDigit(MyCompilerClass.currentToken.charAt(0)) 
                || MyCompilerClass.currentToken.charAt(0) == ' '
                || MyCompilerClass.currentToken.equalsIgnoreCase("Start Bold")
                || MyCompilerClass.currentToken.equalsIgnoreCase("Start Italics")
                || MyCompilerClass.currentToken.equalsIgnoreCase("#Start List")){
			
		if(MyCompilerClass.currentToken.equalsIgnoreCase("#Start Bold"))
 	       {
			bold();
 	       }
		if(MyCompilerClass.currentToken.equals("#NewLine"))
	 	   {
			parseTree.add(MyCompilerClass.currentToken);
			lexims.getNextToken();
	 	   }
		if(MyCompilerClass.currentToken.equals("#Start Use"))
	 	   {
			use();
	 	   }
		if(MyCompilerClass.currentToken.equals("#Start Italics"))
	 	   {
			italics();
	 	   }
		if(MyCompilerClass.currentToken.equals("#Start List"))
	 	   {
			list();
	 	   }
		innertext();
		}
	}
	 //| <bold> <inner-list> | <italics> <inner-list> | <list> <inner-list>	 | <inner-text> <inner-list> | null
	public void innerlist() throws CompilerException {
		// TODO Auto-generated method stub
		while(MyCompilerClass.currentToken.equalsIgnoreCase("#Start Bold")|| MyCompilerClass.currentToken.equals("#Start Italics") 
				                             || MyCompilerClass.currentToken.equalsIgnoreCase("#Start List") 
				                             || MyCompilerClass.currentToken.equalsIgnoreCase("#Start Bold")){
		if(MyCompilerClass.currentToken.equalsIgnoreCase("#Start Bold"))
 	       {
			bold();
 	       }
		if(MyCompilerClass.currentToken.equalsIgnoreCase("#Start Italics"))
	 	   {
			italics();
	 	   }
		if(MyCompilerClass.currentToken.equalsIgnoreCase("#Start List"))
	 	   {
			list();
	 	   }
		innertext();
		}
	}
	
	// <variable-use> <inner-text> | <text> <inner-text> | <newline> <inner-text> 
	public void innertext() throws CompilerException {
		// TODO Auto-generated method stub
		while(MyCompilerClass.currentToken.equalsIgnoreCase("#NewLine") 
				                            || MyCompilerClass.currentToken.equalsIgnoreCase("#Start Use") 
				                            || Character.isLetterOrDigit(MyCompilerClass.currentToken.charAt(0)) 
				                            || MyCompilerClass.currentToken.charAt(0) == ' '){
		if(MyCompilerClass.currentToken.equalsIgnoreCase("#Start Use"))
 	       {
			use();
 	       }
		if(MyCompilerClass.currentToken.equalsIgnoreCase("#NewLine"))
	 	   {
			parseTree.add(MyCompilerClass.currentToken);
			lexims.getNextToken();
	 	   }
		if(text())
	 	   {
			parseTree.add(MyCompilerClass.currentToken);
			 lexims.getNextToken();
	 	   }
		}
	}
	
	public boolean text(){
		if (Character.isLetterOrDigit(MyCompilerClass.currentToken.charAt(0)) || MyCompilerClass.currentToken.charAt(0) == ' ')
			return true;
		else 
			return false;
	}

}
